package com.back.controller;

import com.back.common.enums.RoleCode;
import com.back.entity.Employer;
import com.back.entity.JobSeeker;
import com.back.service.IEmployerService;
import com.back.service.IJobSeekerService;
import com.back.service.IUserService;
import com.back.vo.NamePwdVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.back.common.enums.DeleteFlag;
import com.back.common.utils.GsonUtil;
import com.back.common.utils.JwtUtil;
import com.back.common.utils.MD5Util;
import com.back.common.utils.MailUtil;
import com.back.common.utils.RedisUtil;
import com.back.common.utils.Result;
import com.back.entity.EmailCodeLoginResult;
import com.back.entity.User;
import com.back.vo.EmailLoginVo;
import com.back.vo.EmailRegisterVo;
import com.back.vo.JwtVo;
import com.back.vo.MailVo;
import com.back.vo.NamePwdLoginVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import static net.sf.jsqlparser.util.validation.metadata.NamedObject.user;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Random;

/**
 * <p>
 * 系统用户表 前端控制器
 * </p>
 *
 * @author lyh
 * @since 2020-07-02
 */
@RestController
@RequestMapping
@Api(tags = "用户登录、注册操作")
@Slf4j
public class LoginController {

    /**
     * 用户服务接口，处理用户相关的业务逻辑
     */
    @Autowired
    private IUserService userService;
    
    @Autowired
    private IEmployerService employerService;
    
    @Autowired
    private IJobSeekerService jobSeekerService;
    /**
     * Redis工具类，用于管理Token和验证码
     */
    @Autowired
    private RedisUtil redisUtil;

    /**
     * 邮件工具类，用于发送验证码邮件
     */
    @Autowired
    private MailUtil mailUtil;
    
    /**
     * 系统发送邮件的邮箱地址
     */
    private static final String FROM_EMAIL = "yeaonaiwohe1212@163.com";

    /**
     * 用户名登录状态标识
     */
    private static final String USER_NAME_STATUS = "0";

    /**
     * 邮箱登录状态标识
     */
    private static final String EMAIL_STATUS = "1";
    
    private String getJwt(User user) {
        // 获取需要保存在 jwt 中的数据
        JwtVo jwtVo = new JwtVo();
        jwtVo.setId(user.getId());
        jwtVo.setName(user.getUsername());
        jwtVo.setEmail(user.getEmail());
        jwtVo.setTime(new Date().getTime());
        jwtVo.setRole(user.getRole());
        // 获取 jwt 数据，设置过期时间为 30 分钟
        String jwt = JwtUtil.getJwtToken(jwtVo, 1000L * 60 * 30);
        // 判断用户是否重复登录（code 有值则重复登录，需要保留最新的登录者，剔除前一个登录者）
        String code = redisUtil.get(String.valueOf(user.getId()));
        // 获取当前时间戳
        Long currentTime = new Date().getTime();
        // 如果 redis 中存在 jwt 数据，则根据时间戳比较谁为最新的登陆者
        if (StringUtils.isNotEmpty(code)) {
            // 获取 redis 中存储的 jwt 数据
            JwtVo redisJwt = GsonUtil.fromJson(String.valueOf(JwtUtil.getTokenBody(code).get("data")), JwtVo.class);
            // redis jwt 大于 当前时间戳，则 redis 中 jwt 为最新登录者，当前登录失败
            if (redisJwt.getTime() > currentTime) {
                return null;
            }
        }
        // 把数据存放在 redis 中，设置过期时间为 30 分钟
        redisUtil.set(String.valueOf(user.getId()), jwt, 60 * 30);
        return jwt;
    }

    /**
     * 用户名密码登录处理
     * 1. 根据登录类型（用户名/邮箱）构建查询条件
     * 2. 验证密码（MD5加密比对）
     * 3. 检查用户状态
     * 4. 生成JWT Token
     *
     * @param account 账号（用户名或邮箱）
     * @param pwd 密码
     * @param status 登录类型（0:用户名登录，1:邮箱登录）
     * @return JWT Token，登录失败返回null
     */
    private NamePwdVo pwdLogin(String account, String pwd, String status) {
        // 新增查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 如果是用户名 + 密码登录，则根据 姓名 + 密码 查找数据
        if (USER_NAME_STATUS.equals(status)) {
            queryWrapper.eq("name", account);
        }
        // 如果是手机号 + 密码登录，则根据 手机号 + 密码 查找数据
        if (EMAIL_STATUS.equals(status)) {
            queryWrapper.eq("email", account);
        }
        // 添加密码条件，密码进行 MD5 加密后再与数据库数据比较
        queryWrapper.eq("password", MD5Util.encrypt(pwd));
        // 获取用户数据
        User sysUser = userService.getOne(queryWrapper);
        String role = sysUser.getRole();
        log.info("用户角色为：{}", role);
        // 如果存在用户数据
        if (sysUser != null) {
            if(sysUser.getDeleted() == DeleteFlag.DELETED.getValue()){
                return null;
            }
            return NamePwdVo.builder().user(sysUser).token(getJwt(sysUser)).build();
        }
        return null;
    }

    /**
     * 邮箱验证码登录处理
     * 1. 验证Redis中的验证码
     * 2. 查询用户信息
     * 3. 检查用户状态
     * 4. 生成JWT Token
     *
     * @deprecated 此方法已迁移到AuthController，请使用新的API
     * @param email 邮箱地址
     * @param code 验证码
     * @return JWT Token，登录失败返回null
     */
    @Deprecated
    private EmailCodeLoginResult codeLogin(String email, String code) {
        // 获取 redis 中存放的验证码
        String redisCode = redisUtil.get(email);
        // 存在验证码，且输入的验证码与 redis 存放的验证码相同,则根据手机号去数据库查询数据
        if (StringUtils.isNotEmpty(redisCode) && code.equals(redisCode)) {
            // 新增查询条件
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            // 根据邮箱去查询数据
            queryWrapper.eq("email", email);
            User user = userService.getOne(queryWrapper);
            // 如果存在用户数据
            if (user != null) {
                if(user.getDeleted() == DeleteFlag.DELETED.getValue()){
                    return null;
                }
                return EmailCodeLoginResult.builder()
                        .token(getJwt(user))
                        .name(user.getUsername())
                        .build();
            }
        }
        return null;
    }

    /**
     * 用户名密码登录接口
     * 接收用户名和密码，验证身份并返回Token
     *
     * @param namePwdLoginVo 包含用户名和密码的登录信息
     * @return 登录结果，成功返回Token
     */
    @ApiOperation(value = "使用用户名、密码登录")
    @PostMapping("/namePwdLogin")
    public Result namePwdLogin(@RequestBody NamePwdLoginVo namePwdLoginVo) {
        NamePwdVo userVo = pwdLogin(namePwdLoginVo.getName(), namePwdLoginVo.getPassword(), USER_NAME_STATUS);
        if (Objects.isNull(userVo)) {
            return Result.error().message("登录失败").code(HttpStatus.SC_UNAUTHORIZED);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("user", userVo.getUser());
        map.put("token", userVo.getToken());
        return Result.ok().message("登录成功").data(map);
    }
    

    /**
     * 用户登出接口
     * 1. 验证用户存在性
     * 2. 清除Redis中的Token
     * 3. 返回一个无效的Token
     *
     * @param userName 用户名
     * @return 登出结果
     */
    @ApiOperation(value = "用户登出")
    @GetMapping("/logout")
    public Result logout(@RequestParam String userName) {
        // 先获取用户数据
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", userName);
        User user = userService.getOne(queryWrapper);
        // 用户存在时
        if (user != null) {
            // 生成并返回一个无效的 token
            String jwt = JwtUtil.getJwtToken(null, 1000L);
            // 删除 redis 中的 token
            redisUtil.del(String.valueOf(user.getId()));
            return Result.ok().message("登出成功").data("token", jwt);
        }
        return Result.error().message("登出失败");
    }
    

    /**
     * 发送邮箱验证码
     * 1. 生成6位随机验证码
     * 2. 构建邮件内容
     * 3. 发送验证码邮件
     * 4. 将验证码存入Redis（5分钟有效期）
     *
     * @deprecated 此接口已迁移到AuthController，请使用/api/auth/send-login-code
     * @param email 目标邮箱地址
     * @return 发送结果
     */
    @Deprecated
    @ApiOperation(value = "发送邮箱验证码（已迁移到/api/auth/send-login-code）")
    @GetMapping("/sendEmailCode")
    public Result sendEmailCode(@RequestParam String email) {
        log.warn("调用已弃用的接口: /sendEmailCode，请使用/api/auth/send-login-code");
        try {
            // 生成6位随机验证码
            String code = String.format("%06d", new Random().nextInt(1000000));
            
            // 构建邮件内容
            MailVo mailVo = new MailVo();
            mailVo.setFrom(FROM_EMAIL);
            mailVo.setTo(new String[]{email});
            mailVo.setCc(new String[]{});
            mailVo.setBcc(new String[]{});
            mailVo.setSubject("再就业管理系统验证码");
            mailVo.setText("您的注册验证码是：" + code + "，有效期5分钟，请勿泄露给他人。");
            
            // 发送邮件
            mailUtil.sendMail(mailVo);
            
            // 将验证码存入Redis，设置5分钟过期
            redisUtil.set(email, code, 300);
            
            return Result.ok().message("验证码发送成功");
        } catch (Exception e) {
            return Result.error().message("验证码发送失败");
        }
    }

    /**
     * 邮箱验证码注册接口
     * 验证邮箱验证码并创建新用户
     *
     * @param emailRegisterVo 包含注册信息的对象
     * @return 注册结果
     */
    @ApiOperation(value = "邮箱验证码注册")
    @PostMapping("/emailRegister")
    public Result emailRegister(@RequestBody EmailRegisterVo emailRegisterVo) {
        if (saveWithEmail(emailRegisterVo)) {
            return Result.ok().message("用户注册成功");
        }
        return Result.error().message("用户注册失败").code(HttpStatus.SC_UNAUTHORIZED);
    }

    /**
     * 邮箱验证码登录接口
     * 验证邮箱和验证码，成功则返回Token
     *
     * @deprecated 此接口已迁移到AuthController，请使用/api/auth/email-login
     * @param emailLoginVo 包含邮箱和验证码的登录信息
     * @return 登录结果，成功返回Token
     */
    @Deprecated
    @ApiOperation(value = "邮箱验证码登录（已迁移到/api/auth/email-login）")
    @PostMapping("/emailLogin")
    public Result emailLogin(@RequestBody EmailLoginVo emailLoginVo) {
        log.warn("调用已弃用的接口: /emailLogin，请使用/api/auth/email-login");
        EmailCodeLoginResult result = codeLogin(emailLoginVo.getEmail(), emailLoginVo.getCode());
        if(result == null || StringUtils.isEmpty(result.getToken())){
            return Result.error().message("登录失败,请检查验证码是否正确").code(HttpStatus.SC_UNAUTHORIZED);
        }
        return Result.ok().message("登录成功").data("token", result.getToken()).data("userName", result.getName());
    }

    /**
     * 邮箱验证码注册的具体实现
     * 1. 验证Redis中的验证码
     * 2. 检查用户名是否已存在
     * 3. 创建新用户记录
     * @param emailRegisterVo 注册信息
     * @return 注册是否成功
     */
    private boolean saveWithEmail(EmailRegisterVo emailRegisterVo) {
        // 判断 redis 中是否存在验证码
        String code = redisUtil.get(emailRegisterVo.getEmail());
        // redis 中存在验证码且与当前验证码相同
        if (StringUtils.isNotEmpty(code) && code.equals(emailRegisterVo.getCode())) {
            // 检查用户名是否已存在
            QueryWrapper<User> nameQuery = new QueryWrapper<>();
            nameQuery.eq("name", emailRegisterVo.getUserName());
            if (userService.count(nameQuery) > 0) {
                throw new RuntimeException("用户名已存在");
            }
            
            // 检查邮箱是否已存在
            QueryWrapper<User> emailQuery = new QueryWrapper<>();
            emailQuery.eq("email", emailRegisterVo.getEmail());
            if (userService.count(emailQuery) > 0) {
                throw new RuntimeException("邮箱已被注册");
            }
            User user = setUserProperty(emailRegisterVo);
            return userService.save(user);
        }
        return false;
    }
    public Employer setEmployerProperty(EmailRegisterVo emailRegisterVo){
        Employer employer = new Employer();
        employer.setEmployerName(emailRegisterVo.getEmployerName());
        employer.setAddress(emailRegisterVo.getAddress());
        employer.setServiceCenterId(1L);
        employer.setContactNumber(emailRegisterVo.getContactNumber());
        employerService.save(employer);
        return employer;
    }
    public JobSeeker setJobSeekerProperty(EmailRegisterVo emailRegisterVo){
        JobSeeker jobSeeker = new JobSeeker();
        jobSeeker.setName(emailRegisterVo.getUserName());
        jobSeeker.setGender(emailRegisterVo.getGender());
        jobSeeker.setAge(emailRegisterVo.getAge());
        jobSeeker.setContactNumber(emailRegisterVo.getContactNumber());
        jobSeekerService.save(jobSeeker);
        return jobSeeker;
    }
    public User setUserProperty(EmailRegisterVo emailRegisterVo){
        User user = User.builder().build();
        user.setUsername(emailRegisterVo.getUserName());
        user.setPhone(emailRegisterVo.getMobile());
        user.setPassword(MD5Util.encrypt(emailRegisterVo.getPassword()));
        user.setEmail(emailRegisterVo.getEmail());
        user.setCreateTime(System.currentTimeMillis());
        user.setDeleted(DeleteFlag.NOT_DELETED.getValue());
        user.setRole(emailRegisterVo.getRole());
        user.setUpdateTime(System.currentTimeMillis());
        return user;
    }
}

